﻿/**************************************************************
 *
 * 命名空间：Sgr.DataCategories.Infrastructure.Repositories
 * 创建时间：2025/3/19
 * 描述：行政区划仓储实现
 *
 **************************************************************/

using Microsoft.EntityFrameworkCore;
using Sgr.Domain.Entities.Auditing;
using Sgr.Domain.Repositories;
using Sgr.Domain.Uow;
using Sgr.EntityFrameworkCore;
using Sgr.Exceptions;
using Sgr.Generator;
using Sgr.DataCategories.Domain;
using Sgr.DataCategories.Domain.AdministrativeDivisions;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Threading;
using Sgr.Domain.Entities;
using Sgr.Modules;
using Sgr.Generator.Segment;

namespace Sgr.DataCategories.Infrastructure.Repositories
{
    /// <summary>
    /// 行政区划仓储实现
    /// </summary>
    public class AdministrativeDivisionRepository<TDbContext> :
        EfCoreTreeNodeBaseRepositoryOfTEntityAndTPrimaryKey<TDbContext, AdministrativeDivision, long>,
        IAdministrativeDivisionRepository where TDbContext : UnitOfWorkDbContext
    {
        private readonly ISegmentNumIdGenerator _numberIdGenerator;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContextProvider"></param>
        /// <param name="auditedOperator">审计操作者</param>
        /// <param name="numberIdGenerator">数字ID生成器</param>
        /// <exception cref="BusinessException">参数为空时抛出异常</exception>
        public AdministrativeDivisionRepository(
            IDbContextProvider<TDbContext> dbContextProvider,
            IAuditedOperator auditedOperator,
            ISegmentNumIdGenerator numberIdGenerator)
            : base(dbContextProvider, auditedOperator)
        {
            _numberIdGenerator = numberIdGenerator ?? throw new ArgumentNullException(nameof(numberIdGenerator));
        }

        /// <summary>
        /// 检查并设置主键Id
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns></returns>
        protected override async Task CheckAndSetIdAsync(AdministrativeDivision entity, CancellationToken cancellationToken = default)
        {
            if (entity.Id == 0)
                entity.Id = await _numberIdGenerator.GetUniqueIdAsync(SegmentNumIdGenerator.DEFAULT_KEY, cancellationToken);
        }

        /// <summary>
        /// 根据行政区划代码获取行政区划
        /// </summary>
        /// <param name="code">行政区划代码</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>行政区划</returns>
        public async Task<AdministrativeDivision?> GetByCodeAsync(string code, CancellationToken cancellationToken = default)
        {
            var dbContext = await GetDbContextAsync(cancellationToken);
            return await dbContext.Set<AdministrativeDivision>()
                .FirstOrDefaultAsync(x => x.Code == code, cancellationToken);
        }

        /// <summary>
        /// 根据行政区划级别获取行政区划列表
        /// </summary>
        /// <param name="level">行政区划级别</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>行政区划列表</returns>
        public async Task<IEnumerable<AdministrativeDivision>> GetByLevelAsync(int level, CancellationToken cancellationToken = default)
        {
            var dbContext = await GetDbContextAsync(cancellationToken);
            return await dbContext.Set<AdministrativeDivision>()
                .Where(x => x.Level == level && x.State == EntityStates.Normal)
                .OrderBy(x => x.OrderNumber)
                .ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 检查行政区划代码是否唯一
        /// </summary>
        /// <param name="code">行政区划代码</param>
        /// <param name="excludeId">需要排除的ID</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>是否存在</returns>
        public async Task<bool> CodeIsUniqueAsync(string code, long? excludeId = null, CancellationToken cancellationToken = default)
        {
            Check.StringNotNullOrEmpty(code, nameof(code));

            var dbContext = await GetDbContextAsync(cancellationToken);
            var query = dbContext.Set<AdministrativeDivision>()
                .AsNoTracking()
                .Where(x => x.Code == code);

            if (excludeId.HasValue)
            {
                query = query.Where(x => x.Id != excludeId.Value);
            }

            // 返回 true 表示唯一，即没有找到重复记录
            return !await query.AnyAsync(cancellationToken);
        }
    }
}